<!-- @format -->

<template>
    <div style="height: 100vh; width: 100%">
        <a-layout style="height: 100%;">
            <a-layout-header style="padding: 5px;border-bottom: 1px solid #eee;background-color: #fff;">
                <a-space>
                    <slot name="toolbar"></slot>
                    <a-button @click="cancel">
                        <template #icon>
                            <icon-import />
                        </template>退出
                    </a-button>
                    <a-button @click="save">
                        <template #icon>
                            <icon-save />
                        </template>保存
                    </a-button>
                    <a-button @click="handleCenter">
                        <template #icon>
                            <icon-shrink />
                        </template>
                        居中
                    </a-button>
                    <a-button @click="handleZoom(true)">
                        <template #icon>
                            <icon-plus-circle />
                        </template>
                        放大
                    </a-button>
                    <a-button @click="handleZoom(false)">
                        <template #icon>
                            <icon-minus-circle />
                        </template>
                        缩小
                    </a-button>
                    <a-button @click="handleRedo">
                        <template #icon>
                            <icon-arrow-right />
                        </template>
                        前进
                    </a-button>
                    <a-button @click="handleUndo">
                        <template #icon>
                            <icon-arrow-left />
                        </template>
                        后退
                    </a-button>
                    <a-button @click="viewAsXML">
                        <template #icon>
                            <icon-code />
                        </template>
                        查看xml
                    </a-button>
                </a-space>
            </a-layout-header>
            <a-layout-content style="position: relative;">
                <div id="bpmnContainer" style="height: 100%"></div>
                <div id="js-properties-panel" class="panel">
                    <div class="bio-properties-panel">
                        <div class="bio-properties-panel-header">
                            <div class="bio-properties-panel-header-icon">
                                <IconFactory :type="title"></IconFactory>
                            </div>
                            <div class="bio-properties-panel-header-labels">
                                <div class="bio-properties-panel-header-type">{{customTranslate(startCase(title))}}
                                </div>
                            </div>
                        </div>
                    </div>
                    <component :is="whichCompoent" :params="params" :element="element" v-if="element"></component>
                </div>
            </a-layout-content>
        </a-layout>

        <a-modal v-model:visible="visible" width="800px" :hide-cancel="true">
            <pre style="max-height: 800px;">
                {{currentXml}}
            </pre>
        </a-modal>
    </div>
</template>

<script setup>
import "bpmn-js/dist/assets/diagram-js.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
import BpmnModeler from "bpmn-js/lib/Modeler";
import customTranslate from "./translate/customTranslate";
import defauleXML from "./lib/defaultBpmnXml";
import ProcessPanel from "./lib/panel/ProcessPanel.vue";
import StartPanel from "./lib/panel/StartPanel.vue";
import UserTaskPanel from "./lib/panel/UserTaskPanel.vue";
import EndPanel from "./lib/panel/EndPanel.vue";
import TaskPanel from "./lib/panel/TaskPanel.vue";
import GatewayPanel from "./lib/panel/GatewayPanel.vue";
import SequenceFlowPanel from "./lib/panel/SequenceFlowPanel.vue";
import flowableModdle from './moddle/flowable.json'
import IconFactory from './lib/IconFactory.jsx'
import { ref, onMounted, provide, reactive, markRaw, nextTick, computed, defineProps, defineEmits } from 'vue';
import { startCase } from 'lodash'

const props = defineProps({
    users: { type: [] },
    groups: { type: [] },
    diagramXML: { type: String },
})

const emits = defineEmits(['onSave', 'onCancel']);

const customTranslateModule = {
    translate: ["value", customTranslate],
};
const modeler = ref({});
const element = ref(null);
const params = reactive({
    processKey: "oo00oo",
    processName: "processName",
});
const visible = ref(false)
const title = ref('Process')
const currentXml = ref('')
const tasks = [
    'bpmn:UserTask',
    'bpmn:Task',
    'bpmn:SendTask',
    'bpmn:ReceiveTask',
    'bpmn:ManualTask',
    'bpmn:BusinessRuleTask',
    'bpmn:ServiceTask',
    'bpmn:ScriptTask'
];
const gateways = [
    'bpmn:InclusiveGateway',
    'bpmn:ExclusiveGateway',
    'bpmn:ParallelGateway',
    'bpmn:EventBasedGateway'
];

provide("bpmnModeler", getBpmnModeler());
provide("users", props.users || []);
provide("groups", props.groups || []);
provide("formConfig", props.formConfig || {});

function getBpmnModeler() {
    return modeler;
}

function initModeler() {
    modeler.value = markRaw(new BpmnModeler({
        container: document.getElementById("bpmnContainer"),
        propertiesPanel: {
            parent: "#js-properties-panel",
        },
        additionalModules: [customTranslateModule],
        moddleExtensions: { flowableModdle },
    }));

    createNewDiagram();
    addListener();
}

function addListener() {
    const eventBus = modeler.value.get("eventBus");
    eventBus.on("selection.changed", (e) => {
        element.value = null;
        const tempElement = e && e.newSelection && e.newSelection[0];
        if (tempElement) {
            nextTick(() => {
                title.value = tempElement.type?.replace("bpmn:", '')
                element.value = tempElement
            })
        } else {
            element.value = modeler.value.get('canvas')._rootElement
            title.value = "Process"
        }
    });

    eventBus.on("root.added", (e) => {
        if (e.element.type === 'bpmn:Process') {
            element.value = null
            nextTick(() => {
                whichCompoent.value = ProcessPanel;
                element.value = e.element
            })
        }
    });

    eventBus.on("element.click", (e) => {
        if (e.element.type === 'bpmn:Process') {
            element.value = null
            whichCompoent.value = ProcessPanel;
            element.value = e.element
        }
    });
}

const whichCompoent = computed(() => {
    const nodeType = element.value?.type;

    if (nodeType == "bpmn:StartEvent") {
        return StartPanel;
    } else if (nodeType == "bpmn:UserTask") {
        return UserTaskPanel;
    } else if (tasks.includes(nodeType)) {
        return TaskPanel;
    } else if (nodeType == 'bpmn:sequenceFlow' || nodeType == 'bpmn:MessageFlow') {
        return SequenceFlowPanel;
    } else if (gateways.includes(nodeType)) {
        return GatewayPanel;
    } else if (nodeType == "bpmn:EndEvent") {
        return EndPanel;
    } else {
        return ProcessPanel;
    }
})

function createNewDiagram() {
    if (props.diagramXML) {
        openDiagram(props.diagramXML);
    } else {
        openDiagram(defauleXML(params.processKey, params.processName));
    }
}

async function openDiagram(diagramXML) {
    console.log(diagramXML);
    try {
        await modeler.value.importXML(diagramXML);
    } catch (err) {
        console.error(err);
    }
}

async function viewAsXML() {
    const { xml } = await modeler.value.saveXML({ format: true });
    currentXml.value = xml
    visible.value = true
    console.log(xml);
}

function handleCenter() {
    modeler.value.get("canvas").zoom("fit-viewport", "auto");
}

function handleZoom(enlarge) {
    let zoom = modeler.value.get('canvas').zoom()
    zoom += (enlarge ? 0.1 : -0.1)
    modeler.value.get('canvas').zoom(zoom)
}

function handleUndo() {
    modeler.value.get('commandStack').undo();
}

function handleRedo() {
    modeler.value.get('commandStack').redo();
}

async function save() {
    const { xml } = await modeler.value.saveXML({ format: true });
    emits('onSave', xml)
}

function cancel() {
    emits('onCancel', {})
}

onMounted(() => {
    initModeler();
});
</script>
<script>
export default {
    name: "flowableModeler4Arco",
};
</script>
<style scoped>
.panel {
    width: 300px;
    float: right;
    position: absolute;
    right: 20px;
    top: 25px;
    border: 1px solid #b9bcc6;
}

.bio-properties-panel-header {
    display: flex;
    flex-direction: row;
    align-items: center;
    font-size: var(--text-size-base);
    padding: 16px 10px;
    background-color: var(--header-background-color);
    border-bottom: 1px solid var(--header-bottom-border-color);
    width: 100%;
    z-index: 10;
    max-height: 64px;
    overflow: hidden;
}

.bio-properties-panel-header-labels {
    overflow: hidden;
    margin-left: 12px;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

.arco-collapse {
    border: unset;
}

.bio-properties-panel {
    border-bottom: 1px solid #b9bcc6;
}
</style>
